package jmu.edu.yjc.service.neo4j.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import jmu.edu.yjc.config.CustomCellWriteHeightConfig;
import jmu.edu.yjc.config.CustomCellWriteWeightConfig;
import jmu.edu.yjc.domain.ResponseResult;
import jmu.edu.yjc.domain.entity.neo4j.NodeEntity.*;
import jmu.edu.yjc.domain.entity.neo4j.RelationEntity.*;
import jmu.edu.yjc.domain.entity.neo4j.vo.RelationVo;
import jmu.edu.yjc.repository.*;
import jmu.edu.yjc.service.neo4j.Neo4jService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

@Service
public class Neo4jServiceImpl implements Neo4jService {
    Logger log = LoggerFactory.getLogger(this.getClass());
    @Autowired
    DisableRepository disableRepository;
    @Autowired
    DepartmentRepository departmentRepository;
    @Autowired
    CheckRepository checkRepository;
    @Autowired
    DrugRepository drugRepository;
    @Autowired
    FoodRepository foodRepository;
    @Autowired
    ProducerRepository producerRepository;
    @Autowired
    SymptomRepository symptomRepository;
    @Override
    public ResponseResult CreateNode() {
        BufferedReader reader;
        Set<Check> checks = new HashSet<>();
        Set<Department> departments = new HashSet<>();
        Set<Disease> diseases = new HashSet<>();
        Set<Drug> drugs = new HashSet<>();
        Set<Food> foods = new HashSet<>();
        Set<Symptom> symptoms = new HashSet<>();
        Map<String, Producer> producerMap = new HashMap<>();
        try {
            ClassPathResource classPathResource = new ClassPathResource("static/medical.json");
            reader = new BufferedReader(new InputStreamReader(classPathResource.getInputStream(), StandardCharsets.UTF_8));
            String line = reader.readLine();
            int count = 1;
            Long start = System.currentTimeMillis();
            while (line != null) {
                log.info("正在处理第" + count++ + "条数据");
                JSONObject obj = JSONObject.parseObject(line);
                String cure_way = obj.getString("cure_way");
                String name = obj.getString("name");
                String desc = obj.getString("desc");
                String cause = obj.getString("cause");
                String prevent = obj.getString("prevent");
                String get_prob = obj.getString("get_prob");
                String easy_get = obj.getString("easy_get");
                String cure_lasttime = obj.getString("cure_lasttime");
                String cured_prob = obj.getString("cured_prob");
                Disease disable = Disease.builder().cause(cause).cureWay(cure_way).desc(desc)
                        .name(name).cureLasttime(cure_lasttime)
                        .easyGet(easy_get).curedProb(cured_prob)
                        .curedProb(cured_prob).prevent(prevent)
                        .getProb(get_prob).build();

                JSONArray symptom = obj.getJSONArray("symptom");
                if (symptom != null) {
                    for (Object o : symptom) {
                        Symptom tmp = Symptom.builder().name(o.toString()).build();
                        symptoms.add(tmp);
                    }
                }
                JSONArray acompany = obj.getJSONArray("acompany");
                if (acompany != null) {
                    for (Object o : acompany) {
                        Disease tmp = new Disease();
                        tmp.setName(o.toString());
                    }
                }
                JSONArray cureDepartment = obj.getJSONArray("cure_department");
                if (cureDepartment != null) {
                    disable.setCureDepartment(obj.getString("cure_department"));
                    int i = 0;
                    while (i + 1 < cureDepartment.size()) {
                        Department big = Department.builder().name(cureDepartment.get(i).toString()).build();
                        departments.add(big);
                        i++;
                        Department small = Department.builder().name(cureDepartment.get(i).toString()).build();
                        departments.add(small);
                        small.setDepartmentRel(DepartmentRel.builder().name("属于").department(big).build());
                    }
                }
                JSONArray commonDrug = obj.getJSONArray("common_drug");
                if (commonDrug != null) {
                    for (Object o : commonDrug) {
                        Drug tmp = Drug.builder().name(o.toString()).build();
                        drugs.add(tmp);
                    }
                }
                JSONArray recommandDrug = obj.getJSONArray("recommand_drug");
                if (recommandDrug != null) {
                    for (Object o : recommandDrug) {
                        Drug tmp = Drug.builder().name(o.toString()).build();
                        drugs.add(tmp);
                    }
                }
                JSONArray notEat = obj.getJSONArray("not_eat");
                if (notEat != null) {
                    for (Object o : notEat) {
                        Food tmp = Food.builder().name(o.toString()).build();
                        foods.add(tmp);
                    }
                }
                JSONArray doEat = obj.getJSONArray("do_eat");
                if (doEat != null) {
                    for (Object o : doEat) {
                        Food tmp = Food.builder().name(o.toString()).build();
                        foods.add(tmp);
                    }
                }
                JSONArray recommandEat = obj.getJSONArray("recommand_eat");
                if (recommandEat != null) {
                    for (Object o : recommandEat) {
                        Food tmp = Food.builder().name(o.toString()).build();
                        foods.add(tmp);
                    }
                }
                JSONArray check = obj.getJSONArray("check");
                if (check != null) {
                    for (Object o : check) {
                        Check tmp = Check.builder().name(o.toString()).build();
                        checks.add(tmp);
                    }
                }
                JSONArray drugDetail = obj.getJSONArray("drug_detail");
                if (drugDetail != null) {
                    for (Object o : drugDetail) {
                        String[] producerArray = o.toString().split("\\(");
                        String producerName = producerArray[0];
                        Drug drug = null;
                        Producer producer = Producer.builder().name(producerName).build();
                        if (producerArray.length > 1) {
                            String drugName = producerArray[1].replace(")", "");
                            drug = Drug.builder().name(drugName).build();
                            drugs.add(drug);
                        }
                        producerMap.put(producerName, producer);
                    }
                }
                diseases.add(disable);
                line = reader.readLine();
            }
            Long end = System.currentTimeMillis();
            log.info("文件处理时间：{}", (end - start) / 1000 + "s");
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    checkRepository.saveAll(checks);
                }
            });
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    drugRepository.saveAll(drugs);
                }
            });
            Thread t3 = new Thread(new Runnable() {
                @Override
                public void run() {
                    foodRepository.saveAll(foods);
                }
            });
            Thread t4 = new Thread(new Runnable() {
                @Override
                public void run() {
                    symptomRepository.saveAll(symptoms);
                }
            });
            Thread t5 = new Thread(new Runnable() {
                @Override
                public void run() {
                    departmentRepository.saveAll(departments);
                }
            });
            Thread t6 = new Thread(new Runnable() {
                @Override
                public void run() {
                    Set<Map.Entry<String, Producer>> entries = producerMap.entrySet();
                    log.info("准备开始处理{}条producer数据", entries.size());
                    AtomicInteger i = new AtomicInteger();
                    List<Producer> producers = new ArrayList<>();
                    entries.forEach(entry -> {
                        producers.add(entry.getValue());
                        i.getAndIncrement();
                        if (i.intValue() % 100 == 0 || i.intValue() == entries.size()) {
                            log.info("正在处理第{}条Producer", i.intValue());
                            producerRepository.saveAll(producers);
                            producers.clear();
                        }
                    });
                }
            });
            Thread t7 = new Thread(new Runnable() {
                @Override
                public void run() {
                    log.info("准备开始处理{}条diseases数据", diseases.size());
                    List<Disease> tmp = new ArrayList<>();
                    AtomicInteger i = new AtomicInteger();
                    diseases.forEach(disease -> {
                        tmp.add(disease);
                        i.getAndIncrement();
                        if (i.intValue() % 100 == 0 || i.intValue() == diseases.size()) {
                            log.info("正在始处理第{}条diseases数据", i.intValue());
                            disableRepository.saveAll(tmp);
                            tmp.clear();
                        }
                    });

                }
            });
            t1.start();
            t2.start();
            t3.start();
            t4.start();
            t5.start();
            t6.start();
            t7.start();
            Long saveEnd = System.currentTimeMillis();
            log.info("保存时间：{}", (saveEnd - end) / 1000 + "s");
        } catch (IOException e) {
            e.printStackTrace();
            return ResponseResult.errorResult(-1,"创建节点失败");
        }
        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult exportRelationFile() {
        BufferedReader reader;
        Set<RelationVo> rels_noteat = new HashSet<>();
        Set<RelationVo> rels_doeat = new HashSet<>();
        Set<RelationVo> rels_recommandeat = new HashSet<>();
        Set<RelationVo> rels_commonddrug = new HashSet<>();
        Set<RelationVo> rels_recommanddrug = new HashSet<>();
        Set<RelationVo> rels_check = new HashSet<>();

        Set<RelationVo> rels_symptom = new HashSet<>();
        Set<RelationVo> rels_acompany = new HashSet<>();
        Set<RelationVo> rels_category = new HashSet<>();
        Set<RelationVo> rels_drugof = new HashSet<>();
        try {
            ClassPathResource classPathResource = new ClassPathResource("static/medical.json");
            reader = new BufferedReader(new InputStreamReader(classPathResource.getInputStream(), StandardCharsets.UTF_8));
            String line = reader.readLine();
            int count = 1;
            Long start = System.currentTimeMillis();
            while (line != null) {
                log.info("正在处理第" + count++ + "条数据");
                JSONObject obj = JSONObject.parseObject(line);
                String cure_way = obj.getString("cure_way");
                String name = obj.getString("name");
                String desc = obj.getString("desc");
                String cause = obj.getString("cause");
                String prevent = obj.getString("prevent");
                String get_prob = obj.getString("get_prob");
                String easy_get = obj.getString("easy_get");
                String cure_lasttime = obj.getString("cure_lasttime");
                String cured_prob = obj.getString("cured_prob");
                Disease disable = Disease.builder().cause(cause).cureWay(cure_way).desc(desc)
                        .name(name).cureLasttime(cure_lasttime)
                        .easyGet(easy_get).curedProb(cured_prob)
                        .curedProb(cured_prob).prevent(prevent)
                        .getProb(get_prob).build();

                JSONArray symptom = obj.getJSONArray("symptom");
                if (symptom != null) {
                    for (Object o : symptom) {
                        Symptom tmp = Symptom.builder().name(o.toString()).build();
                        rels_symptom.add(RelationVo.builder().
                                resName(disable.getName()).
                                relation("症状").
                                tarName(tmp.getName()).build());
                    }
                }
                JSONArray acompany = obj.getJSONArray("acompany");
                if (acompany != null) {
                    for (Object o : acompany) {
                        Disease tmp = new Disease();
                        tmp.setName(o.toString());
                        rels_acompany.add(RelationVo.builder().
                                resName(disable.getName()).
                                relation("并发症").
                                tarName(tmp.getName()).build());
                    }
                }
                JSONArray cureDepartment = obj.getJSONArray("cure_department");
                if (cureDepartment != null) {
                    disable.setCureDepartment(obj.getString("cure_department"));
                    Department department = Department.builder().name(cureDepartment.get(cureDepartment.size() - 1).toString()).build();
                    rels_category.add(RelationVo.builder().
                            resName(disable.getName()).
                            relation("治疗科室").
                            tarName(department.getName()).build());
                }
                JSONArray commonDrug = obj.getJSONArray("common_drug");
                if (commonDrug != null) {
                    for (Object o : commonDrug) {
                        Drug tmp = Drug.builder().name(o.toString()).build();
                        rels_commonddrug.add(RelationVo.builder().
                                resName(disable.getName()).
                                relation("常规用药").
                                tarName(tmp.getName()).build());

                    }
                }
                JSONArray recommandDrug = obj.getJSONArray("recommand_drug");
                if (recommandDrug != null) {
                    for (Object o : recommandDrug) {
                        Drug tmp = Drug.builder().name(o.toString()).build();
                        rels_recommanddrug.add(RelationVo.builder().
                                resName(disable.getName()).
                                relation("推荐用药").
                                tarName(tmp.getName()).build());
                    }
                }
                JSONArray notEat = obj.getJSONArray("not_eat");
                if (notEat != null) {
                    for (Object o : notEat) {
                        Food tmp = Food.builder().name(o.toString()).build();
                        rels_noteat.add(RelationVo.builder().
                                resName(disable.getName()).
                                relation("忌吃").
                                tarName(tmp.getName()).build());
                    }
                }
                JSONArray doEat = obj.getJSONArray("do_eat");
                if (doEat != null) {
                    for (Object o : doEat) {
                        Food tmp = Food.builder().name(o.toString()).build();
                        rels_doeat.add(RelationVo.builder().
                                resName(disable.getName()).
                                relation("宜吃").
                                tarName(tmp.getName()).build());
                    }
                }
                JSONArray recommandEat = obj.getJSONArray("recommand_eat");
                if (recommandEat != null) {
                    for (Object o : recommandEat) {
                        Food tmp = Food.builder().name(o.toString()).build();
                        rels_recommandeat.add(RelationVo.builder().
                                resName(disable.getName()).
                                relation("推荐食物").
                                tarName(tmp.getName()).build());
                    }
                }
                JSONArray check = obj.getJSONArray("check");
                if (check != null) {
                    for (Object o : check) {
                        Check tmp = Check.builder().name(o.toString()).build();
                        rels_check.add(RelationVo.builder().
                                resName(disable.getName()).
                                relation("需检查项目").
                                tarName(tmp.getName()).build());
                    }
                }
                JSONArray drugDetail = obj.getJSONArray("drug_detail");
                if (drugDetail != null) {
                    for (Object o : drugDetail) {
                        String[] producerArray = o.toString().split("\\(");
                        String producerName = producerArray[0];
                        if (producerArray.length > 1) {
                            String drugName = producerArray[1].replace(")", "");
                            rels_drugof.add(RelationVo.builder()
                                    .tarName(producerName).relation("生产药品")
                                    .resName(drugName)
                                    .build());
                        }
                    }
                }
                line = reader.readLine();
            }
            Long end = System.currentTimeMillis();
            log.info("文件处理时间：{}", (end - start) / 1000 + "s");
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    Long start = System.currentTimeMillis();
                    log.info("准备开始处理{}条忌吃数据", rels_noteat.size());
                    easyExcelExport("忌吃",rels_noteat);
                    Long end = System.currentTimeMillis();
                    log.info("处理完成忌吃数据,处理耗时{}秒",(end-start)/1000);
                }
            });
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    Long start = System.currentTimeMillis();
                    log.info("准备开始处理{}条宜吃数据", rels_doeat.size());
                    easyExcelExport("宜吃",rels_doeat);
                    Long end = System.currentTimeMillis();
                    log.info("处理完成宜吃数据,处理耗时{}秒",(end-start)/1000);
                }
            });
            Thread t3 = new Thread(new Runnable() {
                @Override
                public void run() {
                    Long start = System.currentTimeMillis();
                    log.info("准备开始处理{}条常规用药数据", rels_commonddrug.size());
                    easyExcelExport("常规用药",rels_commonddrug);
                    Long end = System.currentTimeMillis();
                    log.info("处理完成常规用药数据,处理耗时{}秒",(end-start)/1000);
                }
            });
            Thread t4 = new Thread(new Runnable() {
                @Override
                public void run() {
                    Long start = System.currentTimeMillis();
                    log.info("准备开始处理{}条需要检查数据", rels_check.size());
                    easyExcelExport("需要检查",rels_check);
                    Long end = System.currentTimeMillis();
                    log.info("处理完成需要检查数据,处理耗时{}秒",(end-start)/1000);
                }
            });
            Thread t5 = new Thread(new Runnable() {
                @Override
                public void run() {
                    Long start = System.currentTimeMillis();
                    log.info("准备开始处理{}条治疗科室数据", rels_category.size());
                    easyExcelExport("治疗科室",rels_category);
                    Long end = System.currentTimeMillis();
                    log.info("处理完成治疗科室数据,处理耗时{}秒",(end-start)/1000);
                }
            });
            Thread t6 = new Thread(new Runnable() {
                @Override
                public void run() {
                    Long start = System.currentTimeMillis();
                    log.info("准备开始处理{}条drugOf数据", rels_drugof.size());
                    easyExcelExport("生产药品",rels_drugof);
                    Long end = System.currentTimeMillis();
                    log.info("处理完成drugOf数据,处理耗时{}秒",(end-start)/1000);
                }
            });
            Thread t7 = new Thread(new Runnable() {
                @Override
                public void run() {
                    Long start = System.currentTimeMillis();
                    log.info("准备开始处理{}条并发症数据", rels_acompany.size());
                    easyExcelExport("并发症",rels_acompany);
                    Long end = System.currentTimeMillis();
                    log.info("处理完成并发症数据,处理耗时{}秒",(end-start)/1000);
                }
            });
            Thread t8 = new Thread(new Runnable() {
                @Override
                public void run() {
                    Long start = System.currentTimeMillis();
                    log.info("准备开始处理{}条推荐用药数据", rels_recommanddrug.size());
                    easyExcelExport("推荐用药",rels_recommanddrug);
                    Long end = System.currentTimeMillis();
                    log.info("处理完成推荐用药数据,处理耗时{}秒",(end-start)/1000);
                }
            });
            Thread t9 = new Thread(new Runnable() {
                @Override
                public void run() {
                    Long start = System.currentTimeMillis();
                    log.info("准备开始处理{}条推荐食物数据", rels_recommandeat.size());
                    easyExcelExport("推荐食物",rels_recommandeat);
                    Long end = System.currentTimeMillis();
                    log.info("处理完成推荐食物数据,处理耗时{}秒",(end-start)/1000);
                }
            });
            Thread t10 = new Thread(new Runnable() {
                @Override
                public void run() {
                    Long start = System.currentTimeMillis();
                    log.info("准备开始处理{}条症状数据", rels_symptom.size());
                    easyExcelExport("症状",rels_symptom);
                    Long end = System.currentTimeMillis();
                    log.info("处理完成症状数据,处理耗时{}秒",(end-start)/1000);
                }
            });
            t1.start();
            t2.start();
            t3.start();
            t4.start();
            t5.start();
            t6.start();
            t7.start();
            t8.start();
            t9.start();
            t10.start();
            Long saveEnd = System.currentTimeMillis();
            log.info("保存时间：{}", (saveEnd - end) / 1000 + "s");
        } catch (IOException e) {
            e.printStackTrace();
            return ResponseResult.errorResult(-1,"导出失败");
        }
        return ResponseResult.okResult();
    }

    private void easyExcelExport(String fileName,Set<RelationVo> rels){
        String exportpath = "D:\\excel\\"+fileName+".xlsx";
        SimpleDateFormat sfd = new SimpleDateFormat("yyyy-MM-dd");
        EasyExcel.write(exportpath,RelationVo.class)
                .excelType(ExcelTypeEnum.XLSX)
                .sheet(sfd.format(new Date()))
                .registerWriteHandler(new CustomCellWriteWeightConfig())
                .registerWriteHandler(new CustomCellWriteHeightConfig())
                .doWrite(rels);
    }
}
